package logx

import (
	"bytes"
	"fmt"
	"strconv"
	"sync/atomic"
	// "time"

	glogx "github.com/tal-tech/go-zero/core/logx"
)

var logging *LoggingT

func init() {
	glogx.Disable()
	glogx.DisableStat()
	logging = &LoggingT{
		toStderr: true,
	}
	logging.SetUp(NewConfig())
}

func SetDefault(l *LoggingT){
    logging = l
}

func Close() {
	logging.Close()
}

// EnableFile: 允许写文件
func EnableFile() {
	logging.EnableFile()
}

// DisableTerminal: 关闭屏幕打印操作
func DisableTerminal() {
	logging.DisableTerminal()
}

func SetLevel(level int) {
	logging.SetLevel(level)
}

func SetVModule(v string) {
	logging.SetVModule(v)
}

func SetTrace(backtrace string) {
	logging.SetTrace(backtrace)
}

//输出日志格式为json
func SetContentType(tp MsgType) {
	logging.SetContentType(tp)
}

// V reports whether verbosity at the call site is at least the requested level.
// The returned value is a boolean of type Verbose, which implements Info, Infoln
// and Infof. These methods will write to the Info log if called.
// Thus, one may write either
//	if glog.V(2) { glog.Info("log this") }
// or
//	glog.V(2).Info("log this")
// The second form is shorter but the first is cheaper if logging is off because it does
// not evaluate its arguments.
//
// Whether an individual call to V generates a log record depends on the setting of
// the -v and --vmodule flags; both are off by default. If the level in the call to
// V is at least the value of -v, or of -vmodule for the source file containing the
// call, the V call will log.
func V(level Level) Verbose {
	return logging.V(level)
}

// Info logs to the INFO log.
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
func Info(args ...interface{}) {
	logging.print(infoLog, args...)
}

// InfoDepth acts as Info but uses depth to determine which call frame to log.
// InfoDepth(0, "msg") is the same as Info("msg").
func InfoDepth(depth int, args ...interface{}) {
	logging.printDepth(infoLog, depth, args...)
}

// Infoln logs to the INFO log.
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
func Infoln(args ...interface{}) {
	logging.println(infoLog, args...)
}

// Infof logs to the INFO log.
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
func Infof(format string, args ...interface{}) {
	logging.printf(infoLog, format, args...)
}

// Warning logs to the WARNING and INFO logs.
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
func Warning(args ...interface{}) {
	logging.print(warningLog, args...)
}

// WarningDepth acts as Warning but uses depth to determine which call frame to log.
// WarningDepth(0, "msg") is the same as Warning("msg").
func WarningDepth(depth int, args ...interface{}) {
	logging.printDepth(warningLog, depth, args...)
}

// Warningln logs to the WARNING and INFO logs.
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
func Warningln(args ...interface{}) {
	logging.println(warningLog, args...)
}

// Warningf logs to the WARNING and INFO logs.
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
func Warningf(format string, args ...interface{}) {
	logging.printf(warningLog, format, args...)
}

// Error logs to the ERROR, WARNING, and INFO logs.
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
func Error(args ...interface{}) {
	logging.print(errorLog, args...)
}

// ErrorDepth acts as Error but uses depth to determine which call frame to log.
// ErrorDepth(0, "msg") is the same as Error("msg").
func ErrorDepth(depth int, args ...interface{}) {
	logging.printDepth(errorLog, depth, args...)
}

// Errorln logs to the ERROR, WARNING, and INFO logs.
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
func Errorln(args ...interface{}) {
	logging.println(errorLog, args...)
}

// Errorf logs to the ERROR, WARNING, and INFO logs.
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
func Errorf(format string, args ...interface{}) {
	logging.printf(errorLog, format, args...)
}

// Fatal logs to the FATAL, ERROR, WARNING, and INFO logs,
// including a stack trace of all running goroutines, then calls os.Exit(255).
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
func Fatal(args ...interface{}) {
	logging.print(fatalLog, args...)
}

// FatalDepth acts as Fatal but uses depth to determine which call frame to log.
// FatalDepth(0, "msg") is the same as Fatal("msg").
func FatalDepth(depth int, args ...interface{}) {
	logging.printDepth(fatalLog, depth, args...)
}

// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs,
// including a stack trace of all running goroutines, then calls os.Exit(255).
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
func Fatalln(args ...interface{}) {
	logging.println(fatalLog, args...)
}

// Fatalf logs to the FATAL, ERROR, WARNING, and INFO logs,
// including a stack trace of all running goroutines, then calls os.Exit(255).
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
func Fatalf(format string, args ...interface{}) {
	logging.printf(fatalLog, format, args...)
}

// Exit logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
func Exit(args ...interface{}) {
	atomic.StoreUint32(&fatalNoStacks, 1)
	logging.print(fatalLog, args...)
}

// ExitDepth acts as Exit but uses depth to determine which call frame to log.
// ExitDepth(0, "msg") is the same as Exit("msg").
func ExitDepth(depth int, args ...interface{}) {
	atomic.StoreUint32(&fatalNoStacks, 1)
	logging.printDepth(fatalLog, depth, args...)
}

// Exitln logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
func Exitln(args ...interface{}) {
	atomic.StoreUint32(&fatalNoStacks, 1)
	logging.println(fatalLog, args...)
}

// Exitf logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
func Exitf(format string, args ...interface{}) {
	atomic.StoreUint32(&fatalNoStacks, 1)
	logging.printf(fatalLog, format, args...)
}

// func SetflushInterval(tm int) {
// flushInterval = time.Duration(tm) * time.Second
// }

// logBridge provides the Write method that enables CopyStandardLogTo to connect
// Go's standard logs to the logs provided by this package.
type logBridge severity

// Write parses the standard logging line and passes its components to the
// logger for severity(lb).
func (lb logBridge) Write(b []byte) (n int, err error) {
	var (
		file = "???"
		line = 1
		text string
	)
	// Split "d.go:23: message" into "d.go", "23", and "message".
	if parts := bytes.SplitN(b, []byte{':'}, 3); len(parts) != 3 || len(parts[0]) < 1 || len(parts[2]) < 1 {
		text = fmt.Sprintf("bad log format: %s", b)
	} else {
		file = string(parts[0])
		text = string(parts[2][1:]) // skip leading space
		line, err = strconv.Atoi(string(parts[1]))
		if err != nil {
			text = fmt.Sprintf("bad line number: %s", b)
			line = 1
		}
	}
	// printWithFileLine with alsoToStderr=true, so standard log messages
	// always appear on standard error.
	logging.printWithFileLine(severity(lb), file, line, true, text)
	return len(b), nil
}
/*
func main() {
	// SetLevel(3)
	// fmt.Println(logging)
	// V(1).Infof("1111\n")
	// V(2).Infof("2222\n")
	// V(3).Infof("3333\n")
	// V(4).Infof("4444\n")

	// EnableFile()
	// Infof("555\n")
	// DisableTerminal()
	// Infof("666\n")
	// Infof("666\n")
	// Infof("666\n")
	// Infof("666\n")
	// Infof("666\n")
	// Infof("666\n")
	// SetContentType(MSG_JSON)
	// // SetContentType(MSG_SELF)

	// t1 := time.Now()
	// for i := 0; i < 100000; i++ {
	// Infof(fmt.Sprintf("%0512d", i+1))
	// }
	// fmt.Println(time.Since(t1))

	// t2 := time.Now()
	// // time.Sleep(time.Second * 30)
	// Close()
	// fmt.Println(time.Since(t1))
	// fmt.Println(time.Since(t2))
	// // SetVModule("log=2")
	// // SetTrace("log.go:1123")
	// // V(4).Infof("666\n")
	// // V(3).Infof("777\n")

	dlog := NewConfig()
	dlog.ServiceName = "mysql"
	dlog.Path = "logs/mysql"
    dlog.MaxSize=  8388608
    dlog.Compress=  true
	defc := NewLog(dlog)
	defc.SetLevel(3)
	fmt.Println(logging)
	defc.V(1).Infof("1111\n")
	defc.V(2).Infof("2222\n")
	defc.V(3).Infof("3333\n")
	defc.V(4).Infof("4444\n")

	defc.EnableFile()
	defc.Infof("555\n")
	defc.DisableTerminal()
	defc.Infof("666\n")
	defc.Infof("666\n")
	defc.Infof("666\n")
	defc.Infof("666\n")
	defc.Infof("666\n")
	defc.Infof("666\n")
	defc.SetContentType(MSG_JSON)
	// SetContentType(MSG_SELF)

	t1 := time.Now()
	for i := 0; i < 100000; i++ {
		defc.Infof(fmt.Sprintf("%0512d", i+1))
	}
	fmt.Println(time.Since(t1))

	t2 := time.Now()
    time.Sleep(time.Second)
	// time.Sleep(time.Second * 30)
	defc.Close()
	fmt.Println(time.Since(t1))
	fmt.Println(time.Since(t2))
	return
}
 */